package com.nidu.demo.file.executor.command;

import cn.hutool.core.util.StrUtil;
import com.nidu.demo.file.ability.FileConfigDomainService;
import com.nidu.demo.file.gateway.FileGateway;
import com.nidu.demo.file.model.File;
import com.nidu.demo.file.model.FileConfig;
import com.nidu.demo.file.storage.FileStorage;
import com.nidu.demo.file.storage.FileStorageFactory;
import com.nidu.demo.tenant.config.TenantContextHolder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

/**
 * 文件上传命令执行器
 *
 * @author auto
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class FileUploadCmdExe {

    private final FileConfigDomainService configDomainService;
    private final FileStorageFactory fileStorageFactory;
    private final FileGateway fileGateway;

    /**
     * 上传文件
     *
     * @param file 文件
     * @param module 模块名称（可选，用于分类存储）
     * @return 文件信息
     */
    @Transactional
    public File uploadFile(MultipartFile file, String module) {
        // 1. 获取当前租户的文件配置
        FileConfig fileConfig = configDomainService.getConfig();
        
        // 2. 获取对应的存储实现
        FileStorage fileStorage = fileStorageFactory.getFileStorage(fileConfig.getStorage());
        
        // 3. 构建存储路径
        String path = buildStoragePath(module);
        
        // 4. 上传文件到存储系统
        String fileKey = fileStorage.upload(file, path, fileConfig.getConfig());
        
        // 5. 生成访问URL
        String fileUrl = fileStorage.getUrl(fileKey, fileConfig.getConfig());
        
        // 6. 保存文件记录到数据库
        File fileEntity = File.create(fileConfig.getId(), file.getOriginalFilename(), fileKey, fileUrl, file.getContentType(), file.getSize());
        
        return fileGateway.create(fileEntity);
    }

    /**
     * 上传文件（指定存储类型）
     *
     * @param file 文件
     * @param module 模块名称
     * @param storageType 存储类型
     * @return 文件信息
     */
    @Transactional
    public File uploadFile(MultipartFile file, String module, Integer storageType) {
        // 1. 获取指定存储类型的配置
        FileConfig fileConfig = configDomainService.getConfigByType(storageType);
        
        // 2. 获取对应的存储实现
        FileStorage fileStorage = fileStorageFactory.getFileStorage(fileConfig.getStorage());
        
        // 3. 构建存储路径
        String path = buildStoragePath(module);
        
        // 4. 上传文件到存储系统
        String fileKey = fileStorage.upload(file, path, fileConfig.getConfig());
        
        // 5. 生成访问URL
        String fileUrl = fileStorage.getUrl(fileKey, fileConfig.getConfig());
        
        // 6. 保存文件记录到数据库
        File fileEntity = File.create(fileConfig.getId(), file.getOriginalFilename(), fileKey, fileUrl, file.getContentType(), file.getSize());
        
        return fileGateway.create(fileEntity);
    }

    /**
     * 删除文件
     *
     * @param fileId 文件ID
     */
    @Transactional
    public void deleteFile(Long fileId) {
        // 1. 获取文件信息
        File file = fileGateway.getById(fileId);
        if (file == null) {
            throw new RuntimeException("文件不存在");
        }
        
        // 2. 获取文件配置
        FileConfig fileConfig = configDomainService.getConfig();
        
        // 3. 获取存储实现
        FileStorage fileStorage = fileStorageFactory.getFileStorage(fileConfig.getStorage());
        
        // 4. 从存储系统删除文件
        try {
            fileStorage.delete(file.getPath(), fileConfig.getConfig());
        } catch (Exception e) {
            log.warn("删除存储文件失败: {}", e.getMessage());
        }
        
        // 5. 删除数据库记录
        fileGateway.deleteById(fileId);
    }

    /**
     * 构建存储路径
     *
     * @param module 模块名称
     * @return 存储路径
     */
    private String buildStoragePath(String module) {
        Long tenantId = TenantContextHolder.getTenantId();
        String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        
        if (StrUtil.isNotEmpty(module)) {
            return String.format("tenant_%d/%s/%s", tenantId, module, date);
        } else {
            return String.format("tenant_%d/common/%s", tenantId, date);
        }
    }

}
